import {EventEmitter} from "../node-test";
import log from './logger'
import {Weighter} from "./interfaces";
import settings from "./settings";
import utils from "./utils";
import {Socket} from "net";

interface DataBuffer {
    buf: string;
    buf2: number[];
}

function convertWeightDataHT9800(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        const t = parseInt(buffer[i]).toString(16)
        dataBuffer.buf += t.length == 1 ? '0' + t : t
    }
    const search = 'ff11'
    const start = dataBuffer.buf.indexOf(search)
    if (start >= 0 && dataBuffer.buf.length > 20) {
        const result = dataBuffer.buf.substr(start + 4, 6);//截取字符串
        const value = parseInt(result.substr(4, 2) + result.substr(2, 2) + result.substr(0, 2)) / 1000
        dataBuffer.buf = ''
        return value;
    }
}

export function convertWeightDataXK3190(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        dataBuffer.buf2.push(buffer[i]);
    }
    const index = dataBuffer.buf2.indexOf(0x02);
    if (index >= 0 && dataBuffer.buf2.length > 20) {
        let dataArray: any = [];
        for (let i = 0; i < 8; i++) {
            dataArray.push(dataBuffer.buf2[index + i + 1]);
        }
        const xor = utils.chk8xor(dataArray);
        const xor1 = String.fromCharCode(dataBuffer.buf2[index + 9]);
        const xor2 = String.fromCharCode(dataBuffer.buf2[index + 10]);
        dataBuffer.buf2 = []
        if (xor1 + xor2 === xor.toString(16).toUpperCase()) {
            dataArray.pop()
            const string = dataArray.map((value: any) => {
                return String.fromCharCode(value);
            }).join('');
            const weight = parseFloat(string)
            return weight / 1000.0;
        }
    }
}

export function convertWeightDataXK31902(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        dataBuffer.buf2.push(buffer[i]);
    }
    let index = dataBuffer.buf2.indexOf(0x02);
    if (index >= 0 && dataBuffer.buf2.length > 20) {
        let dataArray: any = [];
        for (let i = 0; i < 8; i++) {
            dataArray.push(dataBuffer.buf2[index + i + 1]);
        }
        // const xor = utils.chk8xor(dataArray);
        // const xor1 = String.fromCharCode(dataBuffer.buf2[index + 9]);
        // const xor2 = String.fromCharCode(dataBuffer.buf2[index + 10]);
        dataBuffer.buf2 = []
        // if (xor1 + xor2 === xor.toString(16).toUpperCase()) {
        dataArray.pop()
        const string = dataArray.map((value: any) => {
            return String.fromCharCode(value);
        }).join('');
        const weight = parseFloat(string)
        return weight / 1000.0;
        // }
    }
    index = dataBuffer.buf2.indexOf(0x82);
    if (index >= 0 && dataBuffer.buf2.length > 20) {
        let dataArray: any = [];
        for (let i = 0; i < 8; i++) {
            dataArray.push(dataBuffer.buf2[index + i + 1]);
        }
        // const xor = utils.chk8xor(dataArray);
        // const xor1 = String.fromCharCode(dataBuffer.buf2[index + 9]);
        // const xor2 = String.fromCharCode(dataBuffer.buf2[index + 10]);
        dataBuffer.buf2 = []
        // if (xor1 + xor2 === xor.toString(16).toUpperCase()) {
        dataArray.pop()
        const string = dataArray.map((value: any) => {
            return String.fromCharCode(value);
        }).join('');
        const weight = parseFloat(string)
        return weight / 1000.0;
        // }
    }
}

function convertWeightDataXK3190D2(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        const t = String.fromCharCode(buffer[i]);
        dataBuffer.buf += t;
    }
    const index = dataBuffer.buf.indexOf("=");
    if (index >= 0 && dataBuffer.buf.length > 20) {
        let tempWeight = dataBuffer.buf.substring(index + 1, index + 8);
        tempWeight = tempWeight.split("").reverse().join("") //数据倒序
        const weight: number = parseFloat(tempWeight)
        dataBuffer.buf = ""
        return weight / 1000.0;
    }
}

export function convertWeightDataD12(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        const t = String.fromCharCode(buffer[i]);
        dataBuffer.buf += t;
    }
    let index = dataBuffer.buf.indexOf("+");
    if (index >= 0 && dataBuffer.buf.length > 20) {
        const tempWeight = dataBuffer.buf.substring(index + 1, index + 6);
        const weight = parseFloat(tempWeight)
        dataBuffer.buf = ""
        return weight / 100.0;
    }
    index = dataBuffer.buf.indexOf("-");
    if (index >= 0 && dataBuffer.buf.length > 20) {
        const tempWeight = dataBuffer.buf.substring(index + 1, index + 6);
        const weight = parseFloat(tempWeight)
        dataBuffer.buf = ""
        return -weight / 100.0;
    }
}

function convertWeightDataD2008(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        const t = String.fromCharCode(buffer[i]);
        dataBuffer.buf += t;
    }
    const index = dataBuffer.buf.indexOf(String.fromCharCode(0x20));
    if (index >= 0 && dataBuffer.buf.length > 30) {
        const tempWeight = dataBuffer.buf.substring(index + 1, index + 7);
        // log.info(tempWeight, 'index:', index, 'buf:', dataBuffer.buf)
        const weight = parseFloat(tempWeight)
        dataBuffer.buf = ""
        return weight / 1000.0;
    }
}

function convertWeightDataXK3133(buffer: [], dataBuffer: DataBuffer): number | undefined {
    for (let i = 0; i < buffer.length; i++) {
        const t = String.fromCharCode(buffer[i]);
        dataBuffer.buf += t;
        // log.info("tempBuf :", dataBuffer.buf, "tempBufLength :", dataBuffer.buf.length)
    }
    const index = dataBuffer.buf.indexOf(String.fromCharCode(0x20));
    if (index >= 0 && dataBuffer.buf.length > 30) {
        const tempWeight = dataBuffer.buf.substring(index + 1, index + 7);
        // log.info(tempWeight, 'index:', index, 'buf:', dataBuffer.buf)
        const weight = parseFloat(tempWeight)
        dataBuffer.buf = ""
        return weight / 1000.0;
    }
}


function getConvertor(equipmentType: string): any {
    if (equipmentType == 'HT9800') {
        return convertWeightDataHT9800
    } else if (equipmentType == 'XK3190') {
        return convertWeightDataXK3190
    } else if (equipmentType == 'XK31902') {
        return convertWeightDataXK31902
    } else if (equipmentType == "XK3190-D2") {
        return convertWeightDataXK3190D2
    } else if (equipmentType == "D12") {
        return convertWeightDataD12
    } else if (equipmentType == "D2008") {
        return convertWeightDataD2008
    } else if (equipmentType == 'XK3133') {
        return convertWeightDataXK3133
    } else {
        throw new Error('没有找到对应型号')
    }
}

export class WeighterImpl extends EventEmitter implements Weighter {
    socket: Socket
    dataBuffer: DataBuffer = {buf: '', buf2: []}
    oldWeight = 0
    weight = 0
    wen = false
    wenCount = 0
    oldWeightWen = 0
    lastTimestamp = new Date().getTime()
    zeroTimestamp = new Date().getTime()
    available: boolean = false

    public constructor() {
        super();
    }

    checkDataBufferLength(dataBuffer: DataBuffer) {
        if (dataBuffer.buf.length > 200) {
            dataBuffer.buf = ''
            log.info('clear DataBuffer')
        }
        if (dataBuffer.buf2.length > 200) {
            dataBuffer.buf2 = []
            log.info('clear DataBuffer2')
        }
    }

    connect(): void {
        this.socket = new Socket();
        let address = settings.weightAddress.split(':');
        this.socket.connect(parseInt(address[1]), address[0]);
        this.socket.on("connect", () => {
            this.lastTimestamp = new Date().getTime();
            log.info("weightServer on connect");
        })

        this.socket.on("data", (buffer: []) => {
            this.checkDataBufferLength(this.dataBuffer)
            const convertor = getConvertor(settings.equipmentType)
            const tempweight = convertor(buffer, this.dataBuffer)
            if (!isNaN(tempweight)) {
                // if (tempweight < 0) {
                //     return;
                // }
                this.weight = tempweight;
                if (this.oldWeight !== this.weight) {
                    this.oldWeight = this.weight
                    this.wen = false
                    this.emit('weight_data', this.weight, false)
                }
                this.lastTimestamp = new Date().getTime();
                // 更新仪表状态
                this.available = true
            }
        })

        this.socket.on("close", () => {
            this.available = false
            log.info("weightServer on close")
            // setTimeout(() => {
            //     log.info("weightServer reconnect...")
            //     this.connect();
            // }, 10000)
        })

        this.socket.on('error', function (error) {
            this.avaliable = false
            log.info('weightServer on error: ' + error)
            // setTimeout(() => {
            //     log.info("weightServer reconnect...")
            //     this.connect();
            // }, 10000)
        })
    }

    init(): void {
        log.info("重量监听器启动")
        this.connect();
        // 异常事件判断
        setInterval(() => {
            const currentTimestamp = new Date().getTime()
            // 60秒没数据就变0
            if (currentTimestamp - this.lastTimestamp > 60 * 1000) {
                this.weight = 0.0
                this.available = false
                this.emit('weight_data', 0, this.wen)
                this.emit('weight_disconnect')
            }
            // 5分钟没有归0
            if (currentTimestamp - this.zeroTimestamp > 60 * 1000 * 5) {
                this.emit('weight_not_zero')
            }
            // 20秒没数据尝试重连
            if (currentTimestamp - this.lastTimestamp > 20 * 1000) {
                this.socket.end();
                this.socket.destroy();
                this.connect();
            }
        }, 5 * 1000);
        // 稳定监测
        setInterval(() => {
            if (this.oldWeightWen === this.weight) {
                this.wenCount++
                if (this.wenCount % settings.weightWenTimeout === 0 && this.weight !== 0) {
                    this.wen = true
                    this.emit('weight_data', this.weight, true)
                }
            } else {
                this.wen = false
                this.emit('weight_data', this.weight, false)
                this.wenCount = 0
                this.oldWeightWen = this.weight
            }
            // 小于0.2，视为已归0
            if (this.weight < 0.2) {
                this.zeroTimestamp = new Date().getTime();
            }
        }, 1000)
    }
}

const weighter = new WeighterImpl();
export default weighter;